package com.fy.service.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.fy.common.constant.CmdConstants;
import com.fy.common.constant.RedisKeyConstant;
import com.fy.common.dto.GroupMemberRoleDto;
import com.fy.common.dto.MemberGroupInfoEditDto;
import com.fy.common.entity.SkImChatSession;
import com.fy.common.entity.SkImGroup;
import com.fy.common.entity.SkImGroupMember;
import com.fy.common.enums.SkImCommonStatusEnum;
import com.fy.common.enums.SkImGroupEnum;
import com.fy.common.model.im.MessageModel;
import com.fy.common.util.ImUtil;
import com.fy.common.util.TokenUtil;
import com.fy.common.vo.GroupMemberVo;
import com.fy.dao.mapper.SkImGroupMemberMapper;
import com.fy.framework.common.model.R;
import com.fy.framework.component.config.LocaleMessage;
import com.fy.framework.component.config.RedissonComponet;
import com.fy.service.service.ImBrokerService;
import com.fy.service.service.SkImChatSessionService;
import com.fy.service.service.SkImGroupMemberService;
import com.fy.service.service.SkImUserInfoService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.redisson.api.RMapCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author zhshuo
 * @date 2021/12/17 18:29
 */
@Slf4j
@Service
public class SkImGroupMemberServiceImpl extends ServiceImpl<SkImGroupMemberMapper, SkImGroupMember> implements SkImGroupMemberService {

    LocaleMessage localeMessage;

    ImBrokerService imBrokerService;

    RedissonComponet redissonComponet;

    SkImUserInfoService userInfoService;

    SkImChatSessionService chatSessionService;

    @Override
    public void memberGroupInfoEdit(MemberGroupInfoEditDto groupInfoEditDto) {
        baseMapper.memberGroupInfoEdit(groupInfoEditDto.setUserId(TokenUtil.getUserId()));
    }

    @Override
    public void quit(Long groupId) {
        update(new SkImGroupMember().setStatus(SkImGroupEnum.MEMBER_QUIT.getValue()),new EntityWrapper<SkImGroupMember>()
               .eq("sk_im_group_id",groupId).eq("sk_im_user_id",TokenUtil.getUserId()));
        chatSessionService.update(new SkImChatSession().setStatus(SkImCommonStatusEnum.DELETED.getStatus()),new EntityWrapper<SkImChatSession>()
                .eq("session_id", ImUtil.chatSessionIdGenGroup(TokenUtil.getUserId(),groupId)));
        RMapCache<String, Object> map = redissonComponet.getMap(RedisKeyConstant.USER_CHAT_SESSION + TokenUtil.getUserId());
        map.remove(ImUtil.chatSessionIdGenGroup(TokenUtil.getUserId(),groupId));
        RMapCache<String, Object> groupMember = redissonComponet.getMap(RedisKeyConstant.GROUP_MEMBERS+groupId);
        groupMember.remove(String.valueOf(TokenUtil.getUserId()));

        List<Long> ids = new ArrayList<>();
        SkImGroupMember skImGroupMemberOwner = selectOne(new EntityWrapper<SkImGroupMember>().setSqlSelect("sk_im_user_id").eq("user_role", SkImGroupEnum.GROUP_OWNER.getValue()).eq("id", groupId));
        List<SkImGroupMember> skImGroupMemberManager = selectList(new EntityWrapper<SkImGroupMember>().setSqlSelect("sk_im_user_id").eq("user_role", SkImGroupEnum.GROUP_MANAGER.getValue()).eq("id", groupId));
        ids.add(skImGroupMemberOwner.getSkImUserId());
        if(CollectionUtils.isNotEmpty(skImGroupMemberManager)){
            ids.addAll(skImGroupMemberManager.stream().map(SkImGroupMember::getSkImUserId).collect(Collectors.toList()));
        }
        MessageModel messageModel = new MessageModel();
        messageModel.setFrom(TokenUtil.getUserId());
        messageModel.setCmd(CmdConstants.RESPONSE_QUIT_GROUP);
        imBrokerService.commonAddressingMessage(messageModel,ids,false);
        RMapCache<String, Object> mapCache = redissonComponet.getMap(RedisKeyConstant.NIM_USER_INFO);
        if(mapCache.containsKey(TokenUtil.getUserId().toString())){
            JSONObject jsonObject = (JSONObject) mapCache.get(TokenUtil.getUserId().toString());
            Object userGroup = jsonObject.get("userGroup");
            JSONArray jsonArray = new JSONArray();
            if(Objects.nonNull(userGroup)){
                jsonArray = (JSONArray) userGroup;
                jsonArray.remove(groupId);
                jsonObject.put("userGroup",jsonArray);
                mapCache.put(TokenUtil.getUserId().toString(),jsonObject);
            }
        }
        baseMapper.updateGroupMemberCount(groupId,-1);
    }

    @Override
    public void kickOut(Long groupId, Long userId) {
        update(new SkImGroupMember().setStatus(SkImGroupEnum.MEMBER_QUIT.getValue()),new EntityWrapper<SkImGroupMember>()
                .eq("sk_im_group_id",groupId).eq("sk_im_user_id",userId));
        chatSessionService.update(new SkImChatSession().setStatus(SkImCommonStatusEnum.DELETED.getStatus()),new EntityWrapper<SkImChatSession>()
                .eq("session_id", ImUtil.chatSessionIdGenGroup(userId,groupId)));
        RMapCache<String, Object> map = redissonComponet.getMap(RedisKeyConstant.USER_CHAT_SESSION + userId);
        map.remove(ImUtil.chatSessionIdGenGroup(userId,groupId));
        RMapCache<String, Object> groupMember = redissonComponet.getMap(RedisKeyConstant.GROUP_MEMBERS+groupId);
        groupMember.remove(userId.toString());
        MessageModel messageModel = new MessageModel();
        messageModel.setFrom(TokenUtil.getUserId());
        messageModel.setFrom(userId);
        messageModel.setCmd(CmdConstants.RESPONSE_KICK_GROUP);
        imBrokerService.commonAddressingMessage(messageModel, Arrays.asList(userId),false);
        RMapCache<String, Object> mapCache = redissonComponet.getMap(RedisKeyConstant.NIM_USER_INFO);
        if(mapCache.containsKey(TokenUtil.getUserId().toString())){
            JSONObject jsonObject = (JSONObject) mapCache.get(TokenUtil.getUserId().toString());
            Object userGroup = jsonObject.get("userGroup");
            JSONArray jsonArray = new JSONArray();
            if(Objects.nonNull(userGroup)){
                jsonArray = (JSONArray) userGroup;
                jsonArray.remove(groupId);
                jsonObject.put("userGroup",jsonArray);
                mapCache.put(TokenUtil.getUserId().toString(),jsonObject);
            }
        }
        updateGroupMemberCount(groupId,-1);
    }

    @Override
    public R<?> memberRole(GroupMemberRoleDto memberRoleDto) {
        Long groupId = memberRoleDto.getId();
        Long targetUserId = memberRoleDto.getTargetUserId();
        SkImGroupMember groupOwner = selectOne(new EntityWrapper<SkImGroupMember>().eq("sk_im_group_id", groupId).eq("sk_im_user_id", TokenUtil.getUserId()));
        if(!groupOwner.getUserRole().equals(SkImGroupEnum.GROUP_OWNER.getValue())){
            return R.failedAlter(localeMessage.getMessage("im.group.youAreNotTheOwner"));
        }
        SkImGroupMember groupMember = selectOne(new EntityWrapper<SkImGroupMember>().eq("sk_im_group_id", groupId).eq("sk_im_user_id", targetUserId));
        if(memberRoleDto.getRole().equals(SkImGroupEnum.GROUP_OWNER)){
            return R.failedAlter(localeMessage.getMessage("im.common.parameterError"));
        }
        if(groupMember.getUserRole().equals(memberRoleDto.getRole().getValue())){
            return R.failedAlter(localeMessage.getMessage("im.common.parameterError"));
        }

        //TODO 如果是群管理员.这里应该有数量限制
        update(new SkImGroupMember().setUserRole(memberRoleDto.getRole().getValue()),new EntityWrapper<SkImGroupMember>().eq("sk_im_group_id", groupId).eq("sk_im_user_id", targetUserId));
        return R.success(localeMessage.getMessage("im.common.successful"));
    }

    @Override
    public void updateGroupMemberCount(Long groupId, int i) {
        baseMapper.updateGroupMemberCount(groupId,i);
    }

    @Override
    public List<GroupMemberVo> groupMember(Long id) {
            return baseMapper.groupMember(id);
    }

    @Autowired
    public void setLocaleMessage(LocaleMessage localeMessage) {
        this.localeMessage = localeMessage;
    }

    @Autowired
    public void setImBrokerService(ImBrokerService imBrokerService) {
        this.imBrokerService = imBrokerService;
    }

    @Autowired
    public void setRedissonComponet(RedissonComponet redissonComponet) {
        this.redissonComponet = redissonComponet;
    }

    @Autowired
    public void setUserInfoService(SkImUserInfoService userInfoService) {
        this.userInfoService = userInfoService;
    }

    @Autowired
    public void setChatSessionService(SkImChatSessionService chatSessionService) {
        this.chatSessionService = chatSessionService;
    }
}
